package com.xinmao.quantitative.trad.strategies.combine;

import com.xinmao.quantitative.trad.strategies.IStrategy;
import org.springframework.stereotype.Component;
import org.ta4j.core.BarSeries;
import org.ta4j.core.BaseStrategy;
import org.ta4j.core.Rule;
import org.ta4j.core.Strategy;
import org.ta4j.core.indicators.SMAIndicator;
import org.ta4j.core.indicators.bollinger.BollingerBandWidthIndicator;
import org.ta4j.core.indicators.bollinger.BollingerBandsLowerIndicator;
import org.ta4j.core.indicators.bollinger.BollingerBandsMiddleIndicator;
import org.ta4j.core.indicators.bollinger.BollingerBandsUpperIndicator;
import org.ta4j.core.indicators.helpers.ClosePriceIndicator;
import org.ta4j.core.indicators.statistics.StandardDeviationIndicator;
import org.ta4j.core.indicators.volume.ChaikinMoneyFlowIndicator;
import org.ta4j.core.num.DecimalNum;
import org.ta4j.core.num.Num;
import org.ta4j.core.rules.*;

/**
 * bollinger band squeeze Strategy
 *
 * @see <a href="https://school.stockcharts.com/doku.php?id=trading_strategies:bollinger_band_squeeze">
 *      https://school.stockcharts.com/doku.php?id=trading_strategies:bollinger_band_squeeze</a>
 */
@Component
public class BollingerBandStrategy implements IStrategy {

    @Override
    public  Strategy buildStrategy(BarSeries series) {

        ClosePriceIndicator closePrice = new ClosePriceIndicator(series);

        SMAIndicator sma = new SMAIndicator(closePrice, 20);
        BollingerBandWidthIndicator bandwidth = getBollingerBandWidthIndicator(closePrice, sma);

        ChaikinMoneyFlowIndicator cmf = new ChaikinMoneyFlowIndicator(series, 20);



        Rule entryRule = new CrossedDownIndicatorRule(bandwidth, DecimalNum.valueOf(2))
                .and(new OverIndicatorRule(cmf, DecimalNum.valueOf(0.05)))
                .and(new IsRisingRule(cmf, 5));



        Rule exitRule = new CrossedUpIndicatorRule(bandwidth, DecimalNum.valueOf(2))
                .and(new UnderIndicatorRule(cmf, DecimalNum.valueOf(0)))
                .and(new IsFallingRule(cmf, 5));
//                .or(new StopGainRule(closePrice,DecimalNum.valueOf(3)));

        return new BaseStrategy("Bollinger Band",entryRule, exitRule);
    }

    private BollingerBandWidthIndicator getBollingerBandWidthIndicator(ClosePriceIndicator closePrice, SMAIndicator sma) {
        StandardDeviationIndicator standardDeviation = new StandardDeviationIndicator(closePrice, 2);

        BollingerBandsMiddleIndicator bbmSMA = new BollingerBandsMiddleIndicator(sma);
        BollingerBandsUpperIndicator bbuSMA = new BollingerBandsUpperIndicator(bbmSMA, standardDeviation);
        BollingerBandsLowerIndicator bblSMA = new BollingerBandsLowerIndicator(bbmSMA, standardDeviation);

        return new BollingerBandWidthIndicator(bbuSMA, bbmSMA, bblSMA);
    }

    @Override
    public Num getScore() {
        return DecimalNum.valueOf(1);
    }
}
